#pragma once

#include <gtest/gtest.h>
#include <ECS/ECS.h>
#include "Components.h"

namespace ct
{
	struct CCPoint
	{
		float x;
		float y;

		CCPoint() : x(0), y(0) {}
		CCPoint(float _x, float _y) : x(_x), y(_y) {}

		bool operator == (const CCPoint& other) const
		{
			return x== other.x && y == other.y;
		}
	};

	class BaseComponent : public ECS::Component
	{
		mtMETA_DEC;
	public:
		int state;
		CCPoint position;
		BaseComponent() : state(0) 
		{
			position.x = 0;
			position.y = 0;
		}

		void update()
		{
			state++;
		}

		void setPosition(const CCPoint& point)
		{
			position = point;
		}
	};

	class LightSource : public ECS::Component
	{
		mtMETA_DEC;
	public:
		float brightness;
		float radius;

		void onSetPosition(const CCPoint& position)
		{

		}
	};

	class GO : public ECS::Assembly
	{
		mtMETA_DEC;
	public:

		void setPosition(const CCPoint& position)
		{
			eventSetPosition(position);
		}
		Signal<void(const CCPoint& pos)> eventSetPosition;
	};


	mtBEGIN(BaseComponent)
		mtMETHOD(update);
		mtMETHOD(setPosition);
	mtEND

	mtBEGIN(GO)
		mtBASE(ECS::Assembly);
		mtSIGNAL(eventSetPosition, setPosition);
	mtEND


	mtBEGIN(LightSource)
		mtBASE(ECS::Component);
		mtCONSTRUCTOR(void);
		mtVARIABLE(brightness);
		mtVARIABLE(radius);
		mtMETHOD(onSetPosition);
	mtEND
}

TEST(Assembly, getComponent)
{
	ECS::Assembly* a = new ECS::Assembly();

	ct::BaseComponent* c = a->getComponent<ct::BaseComponent>();

	EXPECT_EQ(c, a->getComponent<ct::BaseComponent>());
	delete a;
}

TEST(Assembly, sendMessage)
{
	ECS::Assembly* a = new ECS::Assembly();
	auto* c = a->createComponent<ct::BaseComponent>();

	ecsSEND_MESSAGE(a, update);
	EXPECT_EQ(1, c->state);
	delete a;
}

TEST(Assembly, autoConnections)
{
	auto go = new ct::GO();

	auto component = go->createComponent<ct::BaseComponent>();

	ct::CCPoint pos;
	pos.x = 3.0f;
	pos.y = 4.0f;

	go->setPosition(pos);

	EXPECT_EQ(true, pos == component->position);
	delete go;
}